package com.youlai.auth.service;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.youlai.auth.config.CaptchaProperties;
import com.youlai.auth.model.CaptchaResult;
import com.youlai.common.constant.RedisConstants;
import com.youlai.common.sms.property.AliyunSmsProperties;
import com.youlai.common.sms.service.SmsService;
import com.youlai.common.web.exception.BizException;
import io.micrometer.common.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * 认证服务
 *
 * @author Ray Hao
 * @since 3.1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {

    private final CaptchaProperties captchaProperties;
    private final CaptchaService captchaService;

    private final AliyunSmsProperties aliyunSmsProperties;
    private final SmsService smsService;

    private final StringRedisTemplate redisTemplate;
    private final RedissonClient redissonClient;


    /**
     * 获取图形验证码
     *
     * @return Result<CaptchaResult>
     */
    public CaptchaResult getCaptcha() {

        AbstractCaptcha captcha = captchaService.generate();

        // 验证码文本缓存至Redis，用于登录校验
        String captchaId = IdUtil.fastSimpleUUID();
        redisTemplate.opsForValue().set(
                RedisConstants.CAPTCHA_CODE_PREFIX + captchaId,
                captcha.getCode(),
                captchaProperties.getExpireSeconds(),
                TimeUnit.SECONDS
        );

        CaptchaResult captchaResult = CaptchaResult.builder()
                .captchaId(captchaId)
                .captchaBase64(captcha.getImageBase64Data())
                .build();

        return captchaResult;
    }

    /**
     * 发送登录短信验证码
     *
     * @param mobile 手机号
     * @return true|false 是否发送成功
     */
    public boolean sendLoginSmsCode(String mobile) {
        // 获取短信模板代码
        String templateCode = aliyunSmsProperties.getTemplateCodes().get("login");

        // 生成随机4位数验证码
        String code = RandomUtil.randomNumbers(4);

        // 短信模板: 您的验证码：${code}，该验证码5分钟内有效，请勿泄漏于他人。
        // 其中 ${code} 是模板参数，使用时需要替换为实际值。
        String templateParams = JSONUtil.toJsonStr(Collections.singletonMap("code", code));

        boolean result = smsService.sendSms(mobile, templateCode, templateParams);
        if (result) {
            // 将验证码存入redis，有效期5分钟
            redisTemplate.opsForValue().set(RedisConstants.REGISTER_SMS_CODE_PREFIX + mobile, code, 5, TimeUnit.MINUTES);

            // TODO 考虑记录每次发送短信的详情，如发送时间、手机号和短信内容等，以便后续审核或分析短信发送效果。
        }
        return result;
    }

    /**
     * 获取AccessToken
     *
     * @return AccessToken
     */
    public String getAccessToken() {
        RLock redisAccessTokenKey = redissonClient.getLock("REDIS_ACCESS_TOKEN_KEY");
        try {
            boolean b = redisAccessTokenKey.tryLock(10, 5, TimeUnit.SECONDS);
            if(!b) {

                throw new RuntimeException("获取AccessToken失败");
            }
            String s = redisTemplate.opsForValue().get("wechat:accesstoken");
            log.info("redis获取accesstoken",s);
            if(StringUtils.isBlank(s)){
                //这里的appid和secret最好是从配置文件里获取，这样如果更换了，只需要更改配置文件即可
                String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=******&secret=*********";
                String s1 = HttpUtil.get(url);
                log.info("请求获取accesstoken",s1);
                s = JSONUtil.parseObj(s1).getStr("access_token");
                redisTemplate.opsForValue().set("wechat:accesstoken",s,6500, TimeUnit.SECONDS);
            }
            return s;
        }catch (Exception e) {

            log.info("获取accesstoken,报错",e);
            throw new RuntimeException("获取AccessToken失败");
        }
    }

    // 新增微信手机号解密方法
    public String getWxPhoneNumber(String code) {
        RLock lock = redissonClient.getLock("WX_PHONE_LOCK");
        try {
            lock.lock();
            // 1. 获取access_token
            String accessToken = this.getAccessToken();

            // 2. 调用微信API
            String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
            String response = HttpUtil.post(url, JSONUtil.createObj().set("code", code).toString());

            // 3. 解析响应
            JSONObject json = JSONUtil.parseObj(response);
            if(json.getInt("errcode") != 0) {
                log.error("微信API错误: {}", json);
                throw new BizException("获取手机号失败");
            }

            // 4. 返回手机号
            return json.getJSONObject("phone_info").getStr("phoneNumber");
        } finally {
            lock.unlock();
        }
    }


}
